package org.dromara.crawler.mongo.mongoservice.impl;

import cn.hutool.core.util.ObjectUtil;
import com.mongodb.BasicDBObject;
import com.mongoplus.aggregate.Aggregate;
import com.mongoplus.aggregate.AggregateWrapper;
import com.mongoplus.aggregate.pipeline.Accumulators;
import com.mongoplus.conditions.interfaces.ConditionOperators;
import com.mongoplus.conditions.interfaces.Projection;
import com.mongoplus.conditions.query.LambdaQueryChainWrapper;
import com.mongoplus.mapping.TypeReference;
import com.mongoplus.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.bson.Document;
import org.dromara.crawler.domain.vo.ElementEventVo;
import org.dromara.crawler.domain.vo.ElementTargetVo;
import org.dromara.crawler.mongo.mongodomain.ElementEvent;
import org.dromara.crawler.mongo.mongodomain.ElementTarget;
import org.dromara.crawler.mongo.mongoservice.ElementTargetService;
import org.dromara.crawler.utils.DocConvertUtil;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ElementTargetServiceImpl extends ServiceImpl<ElementTarget> implements ElementTargetService {


    @Override
    public Object queryTargetGroup(String targetInfo) {
        LambdaQueryChainWrapper<ElementTarget> wrapper = this.lambdaQuery();
        if (ObjectUtil.isNotEmpty(targetInfo)) {
            LambdaQueryChainWrapper<ElementTarget> orWrapper = this.lambdaQuery();
            orWrapper.like(ElementTarget::getName, targetInfo);
            orWrapper.like(ElementTarget::getEventFirstLevel, targetInfo);
            orWrapper.like(ElementTarget::getEventSecondLevel, targetInfo);
            wrapper.or(orWrapper);
        }
        AggregateWrapper elementTargetAggregate = new AggregateWrapper();
        elementTargetAggregate.project(Projection.builder().display("target_id", "event_second_level", "name","coordinate").buildList());
        elementTargetAggregate.match(wrapper)
            .addFields(new BasicDBObject("type", "2"))
            .group("$event_second_level", Accumulators.push("docs", "$$ROOT"));
        elementTargetAggregate.sortAsc("_id");
        List<Document> documentList = execute("element_target", elementTargetAggregate, Document.class);
        Map<String, List<ElementTargetVo>> targetMap = documentList.stream()
            .collect(Collectors.toMap(
                d -> d.getString("_id"),
                d -> DocConvertUtil.toEntityList(d.getList("docs", Document.class), ElementTargetVo.class)
            ));
        return targetMap;
    }

    @Override
    public ElementTarget queryTargetByTargetId(String targetId) {
        LambdaQueryChainWrapper<ElementTarget> wrapper = this.lambdaQuery();
        wrapper.eq(ElementTarget::getTargetId, targetId);
        return this.one(wrapper);
    }

    @Override
    public List<ElementTarget> queryListByTargetIds(List<String> targetIds) {
        LambdaQueryChainWrapper<ElementTarget> wrapper = this.lambdaQuery();
        wrapper.in(ElementTarget::getTargetId, targetIds);
        return list(wrapper);
    }

    @Override
    public Document queryTargetDocumentByTargetId(String targetId) {
        LambdaQueryChainWrapper<ElementTarget> wrapper = this.lambdaQuery();
        wrapper.eq(ElementTarget::getTargetId, targetId);
        AggregateWrapper aggregateWrapper = new AggregateWrapper()
            .match(wrapper);
        return execute("element_target", aggregateWrapper, Document.class).get(0);
    }


    private List<Map<String, Object>> execute(String collectionName, Aggregate<?> aggregate) {
        return baseMapper.aggregateList(collectionName, aggregate, new TypeReference<Map<String, Object>>() {
        });
    }


    private <T> List<T> execute(String collectionName, Aggregate<?> aggregate, Class<T> clazz) {
        return baseMapper.aggregateList(collectionName, aggregate, clazz);
    }


}
